﻿using Exceptionless;
using Exceptionless.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Timers;
using Topshelf;

namespace EventViewToExceptionless
{
    class EventViewProcessorService : ServiceControl
    {
        private static Mutex mutex = new Mutex();
        public bool Start(HostControl hostControl)
        {
            System.Timers.Timer timer = new System.Timers.Timer
            {
                Enabled = true,
                Interval = double.Parse(ConfigurationManager.AppSettings["Interval"]),
            };
            timer.Start();
            timer.Elapsed += new System.Timers.ElapsedEventHandler(DisplayEventAndLogInformation);
            return true;
        }

        public bool Stop(HostControl hostControl)
        {
            return true;
        }

        private static void DisplayEventAndLogInformation(object source, ElapsedEventArgs e)
        {
            mutex.WaitOne();
            var dateTimeNow = DateTime.Now;
            var timer = ConfigurationManager.AppSettings["Timer"].ToString();
            if (!string.IsNullOrWhiteSpace(timer)
                && !(dateTimeNow.Hour == int.Parse(timer.Split(':')[0].ToString())
                && dateTimeNow.Minute == int.Parse(timer.Split(':')[1].ToString())))
            {
                mutex.ReleaseMutex();
                return;
            }

            //gt:大于;lt：小于
            //事件查看器的查询语句
            var eventviewPath = "Application";
            var query = string.Format("<QueryList><Query Id = \"0\" Path =\"{0}\"><Select Path =\"{0}\"> *[System[(Level = 2 or Level = 3) and TimeCreated[@SystemTime &gt;= '{1}'and @SystemTime&lt;='{2}']]]</Select></Query></QueryList>",
                eventviewPath, ReadFile().ToUniversalTime().ToString("o"), dateTimeNow.ToUniversalTime().ToString("o"));//此刻之前日志

            var elq = new EventLogQuery(eventviewPath, PathType.LogName, query);//如果是Application，PathType改为LogName
            EventLogReader logReader = new EventLogReader(elq);

            for (EventRecord eventInstance = logReader.ReadEvent();
                null != eventInstance; eventInstance = logReader.ReadEvent())
            {
                //.net日志且级别大于等于警告
                var providerName = eventInstance.ProviderName;
                if (!(eventInstance.Level <= 3 &&
                    (providerName.ToLower().Contains("asp.net")
                    || providerName.ToLower().Contains("application error")))) continue;

                var doc = eventInstance.ToXml();

                try
                {
                    var dto = ConvertHelper.GetLogAnalysisDto(doc);

                    ExceptionlessClient.Default.CreateLog(eventInstance.ProviderName, $"事件查看器：{eventInstance.LogName}", "Info")
                     .SetProperty(nameof(dto.Website), dto.Website)//扩展字段
                     .SetProperty(nameof(dto.UserIp), dto.UserIp)
                     .SetProperty(nameof(dto.UserId), dto.UserId)
                     .SetProperty(nameof(dto.Url), dto.Url)
                     .SetProperty(nameof(dto.TimeCreated), dto.TimeCreated)
                     .SetProperty(nameof(dto.ServerName), dto.ServerName)
                     .SetProperty(nameof(eventInstance.TimeCreated), eventInstance.TimeCreated)
                     .SetProperty(nameof(dto.EventID), dto.EventID)
                     .SetProperty(nameof(dto.ErrorMessage), dto.ErrorMessage)
                     .SetProperty(nameof(eventInstance.Level), eventInstance.Level)
                     //.SetProperty(nameof(eventInstance.LevelDisplayName), eventInstance.LevelDisplayName)//可能为空
                     .AddTags("EventView")
                     .SetUserDescription("", eventInstance.FormatDescription())
                     .Submit();
                    WriteFile(eventInstance.TimeCreated.Value);
                }
                catch (EventLogException ex)
                {
                    mutex.ReleaseMutex();
                    ex.ToExceptionless().Submit();
                }
            }
            mutex.ReleaseMutex();
        }

        /// <summary>
        /// 写入时间
        /// </summary>
        /// <param name="time"></param>
        private static void WriteFile(DateTime time)
        {
            string path = @"c:\temp\MyTest.txt";
            if (!File.Exists(path))
            {
                using (FileStream fs = File.Create(path)) { }
            }

            using (FileStream fs = File.OpenWrite(path))
            {
                Byte[] info = new UTF8Encoding(true).GetBytes(time.ToString("yyyy-MM-dd HH:mm:ss"));

                fs.Write(info, 0, info.Length);
            }
        }

        /// <summary>
        /// 从文件读取最后一个时间
        /// </summary>
        /// <returns></returns>
        private static DateTime ReadFile()
        {
            try
            {
                string path = @"c:\temp\MyTest.txt";
                if (!File.Exists(path))
                {
                    using (FileStream fs = File.Create(path))
                    {
                        DateTime time = DateTime.Now.AddDays(-1);
                        Byte[] info = new UTF8Encoding(true).GetBytes(time.ToString("yyyy-MM-dd HH:mm:ss"));
                        fs.Write(info, 0, info.Length);
                        return time;
                    }
                }

                using (StreamReader sr = File.OpenText(path))
                {
                    string s = string.Empty;
                    while ((s = sr.ReadLine()) != null)
                    {
                        return DateTime.Parse(s);
                    }
                    return DateTime.Parse(s);
                }
            }
            catch (Exception ex)
            {
                ex.ToExceptionless().Submit();
            }
            return DateTime.Now;
        }

        //用于循环所有日志
        private static void GetLog()
        {
            EventLog eventlog = new EventLog();
            eventlog.Log = "Application";
            //"Application"应用程序, "Security"安全, "System"系统
            EventLogEntryCollection eventLogEntryCollection = eventlog.Entries;
            foreach (EventLogEntry entry in eventLogEntryCollection)
            {
                //if (entry.EventID == 4624)
                //{
                //    continue;
                //}
                string info = string.Empty;
                if (entry.Source.ToString().ToLower().Contains("asp.net"))
                {
                    info += "类型：" + entry.EntryType.ToString() + ";";
                    info += "日期" + entry.TimeGenerated.ToLongDateString() + ";";
                    info += "时间" + entry.TimeGenerated.ToLongTimeString() + ";";
                    info += "来源" + entry.Source.ToString() + ";";
                    //info += "信息" + entry.Message.ToString() + ";";
                    Console.WriteLine(info);
                }
            }
        }

        /// <summary>
        /// 追加文本
        /// </summary>
        /// <param name="str"></param>
        private static void WriteFileAppend(string str)
        {
            using (TextWriter tw = new StreamWriter("F:/JobGit/LogAnalysis/src/TestCollectWindowsLog/bin/Debug/222.txt", true))
            {
                tw.WriteLine(str);
            }
        }
    }
}
